import logging
import sys
import os
import uuid

from protorpc import remote
from protorpc import messages
from protorpc import message_types
import configs
from models import *
from configs import *

package = 'ShowUp'

sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'site-packages'))

from timeutils import get_current_time, to_pretty_date
from twilio.rest import TwilioRestClient
import bitly_api



class ConfirmationStatus():
    unsent = 0
    sent = 1
    confirmed = 2
    declined = 3


class CustomerMessage(messages.Message):
    id = messages.StringField(1)
    name = messages.StringField(2,required=True)
    phone_number = messages.StringField(3, required=True)
    email = messages.StringField(4)
    address = messages.StringField(5)
    deleted = messages.BooleanField(6)
    last_updated = messages.IntegerField(7)


class BusinessMessage(messages.Message):
    id = messages.StringField(1)
    name = messages.StringField(2, required=True)
    business_name = messages.StringField(3, required=True)
    email = messages.StringField(4)
    phone_number = messages.StringField(5)
    address = messages.StringField(6)
    notification_message = messages.StringField(7, required=True)
    notification_time = messages.IntegerField(8, required=True)
    last_updated = messages.IntegerField(9)


class CustomerCollection(messages.Message):
    """Collection of Customers."""
    items = messages.MessageField(CustomerMessage, 1, repeated=True)


class AppointmentMessage(messages.Message):
    id = messages.StringField(1)
    customer = messages.MessageField(CustomerMessage, 10)
    title = messages.StringField(2,required=True)
    start_time = messages.IntegerField(3, required=True)
    duration = messages.IntegerField(4, required=True)
    notes = messages.StringField(5)
    repeated = messages.IntegerField(6)
    confirmation_status = messages.IntegerField(7)
    deleted = messages.BooleanField(9)
    last_updated = messages.IntegerField(11)
    timezone = messages.StringField(12)
    confirmation_time = messages.IntegerField(13)
    notification_time = messages.IntegerField(15)
    remote_id = messages.StringField(8)
    short_url = messages.StringField(14)


class WebAppointmentMessage(messages.Message):
    appointment = messages.MessageField(AppointmentMessage, 1)
    business = messages.MessageField(BusinessMessage, 2)


class AppointmentCollection(messages.Message):
    """Collection of Appointments."""
    items = messages.MessageField(AppointmentMessage, 1, repeated=True)


class UpdatesCollection(messages.Message):
    appointments = messages.MessageField(AppointmentMessage, 1, repeated=True)
    customers = messages.MessageField(CustomerMessage, 2, repeated=True)
    business_info = messages.MessageField(BusinessMessage, 3)


def create_customer_message(customer):
    return CustomerMessage(id=str(customer.key.id()),
                                    name=customer.name,
                                    phone_number=customer.phone_number,
                                    email=customer.email,
                                    address=customer.address,
                                    deleted=customer.deleted,
                                    last_updated=customer.last_updated)


def create_business_message(business):
    if not business:
        return None
    return BusinessMessage(
            id=str(business.key.id()),
            name=business.name,
            business_name=business.business_name,
            phone_number=business.phone_number,
            email=business.email,
            address=business.address,
            notification_message=business.notification_message,
            notification_time=business.notification_time,
            last_updated=business.last_updated)


def create_appointment_message(appointment):
    return AppointmentMessage(
            id = str(appointment.key.id()),
            title = appointment.title,
            start_time = appointment.start_time,
            duration = appointment.duration,
            notes = appointment.notes,
            repeated = appointment.repeated,
            confirmation_status = appointment.confirmation_status,
            deleted = appointment.deleted,
            last_updated = appointment.last_updated,
            customer = create_customer_message(appointment.customer.get()))


@endpoints.api(name='showup', version='v1',)
class ShowUpApi(remote.Service):
    """ShowUp API v1."""

    def get_endpoints_current_user(self, raise_unauthorized=True):
        current_user = endpoints.get_current_user()
        if raise_unauthorized and current_user is None:
            raise endpoints.UnauthorizedException('Invalid token.')
        return current_user

    LastUpdatedResourceContainer = endpoints.ResourceContainer(
        message_types.VoidMessage,
        timestamp=messages.IntegerField(1, required=True))

    @endpoints.method(LastUpdatedResourceContainer, UpdatesCollection,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='update/{timestamp}', http_method='GET',
                      name='updates.list')
    def get_updates(self, request):
        appointment_query = Appointment.query(ndb.AND(Appointment.user == self.get_endpoints_current_user(),
                                                      Appointment.last_updated > request.timestamp))
        appointments = [create_appointment_message(appointment)
                        for appointment in appointment_query.fetch()]

        customer_query = Customer.query(ndb.AND(Customer.user == self.get_endpoints_current_user(),
                                                Customer.last_updated > request.timestamp))
        customers = [create_customer_message(customer)
                     for customer in customer_query.fetch()]

        business = BusinessInfo.query(ndb.AND(BusinessInfo.user == self.get_endpoints_current_user(),
                                              BusinessInfo.last_updated > request.timestamp)).get()

        return UpdatesCollection(appointments=appointments, customers=customers, business_info=create_business_message(business))

    @endpoints.method(AppointmentMessage, AppointmentMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='appointment', http_method='POST',
                      name='appointment.add')
    def add_appointment(self, request):
        logging.info("add_appointment [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        customer = Customer.query(ndb.AND(Customer.phone_number == request.customer.phone_number,
                                  Customer.user == self.get_endpoints_current_user())).get()
        if not customer:
            logging.info("No customer found with phone number %s for user, creating new customer" % request.customer.phone_number)
            customer = Customer(
                user=self.get_endpoints_current_user(),
                name=request.customer.name,
                phone_number=request.customer.phone_number,
                email=request.customer.email,
                address=request.customer.address,
                deleted=False,
                last_updated=get_current_time())
        else:
            logging.info("Customer with phone number %s exists" % request.customer.phone_number)
            if customer.name != request.customer.name or customer.email != request.customer.email or customer.address != request.customer.address:
                logging.info("Customer data changed, updating")
                customer.name = request.customer.name
                customer.email = request.customer.email
                customer.address = request.customer.address
                customer.last_updated = get_current_time()
        customer.put()

        bi = self.get_user_business_info()

        apt = Appointment(user=self.get_endpoints_current_user(),
                          customer=customer.key,
                          title=request.title,
                          start_time=request.start_time,
                          notification_time=request.start_time-24*60*60,
                          duration=request.duration,
                          notes=request.notes,
                          confirmation_status=ConfirmationStatus.unsent,
                          repeated=request.repeated,
                          deleted=False,
                          confirmation_token=str(uuid.uuid4()).replace("-", ""),
                          last_updated=get_current_time())

        from google_calendar import GoogleCalendar
        remote_id = GoogleCalendar.create_appointment(apt, bi)
        apt.remote_id = remote_id

        logging.debug("Saving new appointment")
        apt.put()
        logging.info("Appointment saved")

        return AppointmentMessage(id=str(apt.key.id()),
                                          title=apt.title,
                                          start_time=apt.start_time,
                                          duration=apt.duration,
                                          notes=apt.notes,
                                          repeated=apt.repeated,
                                          confirmation_status=apt.confirmation_status,
                                          deleted=False,
                                          last_updated=get_current_time(),
                                          customer=create_customer_message(customer))

    AppointmentIdResourceContainer = endpoints.ResourceContainer(
        message_types.VoidMessage,
        id=messages.StringField(1, required=True),
        token=messages.StringField(2, required=True))
    
    @endpoints.method(AppointmentIdResourceContainer, WebAppointmentMessage,
                      path='appointment/{id}/{token}', http_method='GET',
                      name='appointment.get')
    def get_appointment(self, request):

        logging.info("get_appointment [request: %s]" % (request))
        apt = Appointment.get_by_id(int(request.id))

        if not apt or apt.deleted:
            logging.error("appointment with id %s does not exist or deleted" % (request.id))
            raise endpoints.api_exceptions.BadRequestException('Appointment does not exist')
        if (request.token != apt.confirmation_token):
            logging.error("request uses invalid token" % (request.id))
            raise endpoints.api_exceptions.BadRequestException('Bad token')

        logging.debug("getting bussines info [user %s]" % (apt.user))
        business_info = BusinessInfo.query(BusinessInfo.user == apt.user).get()

        return WebAppointmentMessage(appointment=create_appointment_message(apt),
                               business=create_business_message(business_info))

    @endpoints.method(message_types.VoidMessage, AppointmentCollection,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='appointment', http_method='GET',
                      name='appointments.list')
    def get_appointments(self, request):
        logging.info("get_appointments [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        appointment_query = Appointment.query(ndb.AND(Appointment.user==self.get_endpoints_current_user(),
                                                      Appointment.deleted == False))
        appointments = [create_appointment_message(appointment)
                        for appointment in appointment_query.fetch()]

        return AppointmentCollection(items=appointments)


    def get_user_business_info(self):
        bi = BusinessInfo.query(BusinessInfo.user == self.get_endpoints_current_user()).get()
        if not bi:
            logging.error("User does not have associated business info")
            raise endpoints.api_exceptions.BadRequestException('User does not have associated business info')
        return bi

    @endpoints.method(AppointmentMessage, AppointmentMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='appointment', http_method='PUT',
                      name='appointment.edit')
    def edit_appointment(self, request):
        logging.info("edit_appointment [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        apt = Appointment.get_by_id(int(request.id))
        if not apt or apt.deleted:
            logging.error("appointment with id %s does not exist or deleted" % (request.id))
            raise endpoints.api_exceptions.BadRequestException('Appointment does not exist')

        bi = self.get_user_business_info()

        customer = request.customer
        if customer.id != str(apt.customer.id()):
            logging.info("Appointment's customer changes. Get requested customer.")
            customer = Customer.query(ndb.AND(Customer.phone_number == request.customer.phone_number,
                                    Customer.user == self.get_endpoints_current_user())).get()
            if not customer:
                logging.info("Appointment's new customer doesn't exist. Create new customer.")
                customer = Customer(user=self.get_endpoints_current_user(),
                                    name=request.customer.name,
                                    phone_number=request.customer.phone_number,
                                    email=request.customer.email,
                                    address=request.customer.address,
                                    deleted=False,
                                    last_updated=get_current_time())
            else:
                logging.info("Appointment's new customer exist. Update customer.")
                customer.name = request.customer.name
                customer.phone_number = request.customer.phone_number
                customer.email = request.customer.email
                customer.address = request.customer.address
                customer.deleted = False
                customer.last_updated = get_current_time()
            logging.debug("Saving customer.")
            customer.put()
            logging.info("Customer saved.")
            apt.customer = customer.key

        apt.id = request.id
        apt.title = request.title
        apt.start_time = request.start_time
        apt.duration = request.duration
        apt.notes = request.notes
        apt.repeated = request.repeated
        apt.confirmation_status = request.confirmation_status
        apt.last_updated = get_current_time()

        from google_calendar import GoogleCalendar
        remote_id = GoogleCalendar.edit_appointment(apt, bi)
        apt.remote_id = remote_id

        logging.debug("Saving appointment.")
        apt.put()
        logging.info("Appointment saved.")
        return create_appointment_message(apt)

    IdResourceContainer = endpoints.ResourceContainer(
        message_types.VoidMessage,
        id=messages.StringField(1, required=True))


    @endpoints.method(IdResourceContainer, message_types.VoidMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='appointment/{id}', http_method='DELETE',
                      name='appointment.delete')
    def delete_appointment(self, request):
        logging.info("delete_appointment [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        apt = ndb.Key(Appointment, int(request.id)).get()
        if not apt:
            logging.error("appointment %s not found. Appointment can not be deleted." % (request.id))
            raise endpoints.api_exceptions.BadRequestException('Appointment does not exist')
        if apt.user != self.get_endpoints_current_user():
            logging.error("User with id %s is unauthorized to delete appointment." % (self.get_endpoints_current_user()))
            endpoints.UnauthorizedException('Unauthorized')

        logging.debug("Deleting appointment.")
        apt.deleted = True
        apt.last_updated = get_current_time()

        bi = self.get_user_business_info()
        from google_calendar import GoogleCalendar
        GoogleCalendar.delete_appointment(apt, bi)

        apt.put()
        logging.info("Appointment deleted.")
        return message_types.VoidMessage()

    @endpoints.method(CustomerMessage, CustomerMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='customer', http_method='PUT',
                      name='customer.edit')
    def edit_customer(self, request):
        logging.info("edit_customer [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        customer = ndb.Key(Customer, int(request.id)).get()

        if not customer:
            logging.error("Customer with id %s does not exist or deleted" % request.id)
            raise endpoints.api_exceptions.BadRequestException('Customer does not exist')

        if customer.user != self.get_endpoints_current_user():
            endpoints.UnauthorizedException('Unauthorized')

        logging.info("Customer info for user %s exists, updating", self.get_endpoints_current_user())
        customer.name = request.name
        customer.phone_number = request.phone_number
        customer.email=request.email
        customer.address=request.address
        customer.deleted=False
        customer.last_updated=get_current_time()


        logging.debug("Saving customer's changes")
        customer.put()
        logging.info("Customer saved")

        return create_customer_message(customer)

    @endpoints.method(CustomerMessage, CustomerMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='customer', http_method='POST',
                      name='customer.add')
    def add_customer(self, request):
        logging.info("add_customer [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        customer = Customer.query(ndb.AND(Customer.phone_number == request.phone_number,
                                          Customer.user == self.get_endpoints_current_user())).get()
        if customer:
            logging.error("Customer with id %s already exists. Customer can not be created" % request.id)
            raise endpoints.api_exceptions.BadRequestException('Customer already exists')

        logging.info("Creating new customer")
        customer = Customer(user=self.get_endpoints_current_user(),
                            name=request.name,
                            phone_number=request.phone_number,
                            email=request.email,
                            address=request.address,
                            deleted=False,
                            last_updated=get_current_time()
        )
        logging.debug("Saving new customer")
        customer.put()
        logging.info("Customer saved")

        return create_customer_message(customer)

    @endpoints.method(message_types.VoidMessage, CustomerCollection,
                      path='customer', http_method='GET',
                      name='customers.list')

    def get_customers(self, request):
        customer_query = Customer.query(
            ndb.AND(Customer.user == self.get_endpoints_current_user(),
                    Customer.deleted == False))
        customers = [create_customer_message(customer)
                     for customer in customer_query.fetch()]

        return CustomerCollection(items=customers)

    @endpoints.method(IdResourceContainer, message_types.VoidMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='customer', http_method='DELETE',
                      name='customer.delete')
    def delete_customer(self, request):
        logging.info("delete_customer [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        customer = Customer.get_by_id(int(request.id))
        if not customer:
            logging.error("Customer with id %s does not exist. Customer can not be deleted" % request.id)
            raise endpoints.api_exceptions.BadRequestException('Customer does not exist')

        customer.deleted = True
        customer.last_updated = get_current_time()
        logging.debug("Deleting customer")
        customer.put()
        logging.info("Customer deleted")

        return message_types.VoidMessage()

    @endpoints.method(message_types.VoidMessage, BusinessMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='business', http_method='GET',
                      name='business.get')
    def get_business_info(self, request):
        logging.info("get_business_info [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        business = BusinessInfo.query(BusinessInfo.user==self.get_endpoints_current_user()).get()
        if not business:
            logging.error("Business does not exist")
            endpoints.api_exceptions.ForbiddenException('Business does not exist')
        return create_business_message(business)

    @endpoints.method(BusinessMessage, BusinessMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='business', http_method='POST',
                      name='business.edit')
    def edit_business_info(self, request):
        logging.info("edit_business_info [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        business = BusinessInfo.query(BusinessInfo.user==self.get_endpoints_current_user()).get()

        if business:
            logging.info("Business info for user %s exists, updating", self.get_endpoints_current_user())
            business.name=request.name
            business.business_name=request.business_name
            business.phone_number=request.phone_number
            business.email=request.email
            business.address=request.address
            business.notification_message=request.notification_message
            business.notification_time=request.notification_time
            business.last_updated=get_current_time()
        else:
            logging.info("Business info for user %s does not exists", self.get_endpoints_current_user())
            business = BusinessInfo(
                user=self.get_endpoints_current_user(),
                name=request.name,
                business_name=request.business_name,
                phone_number=request.phone_number,
                email=request.email,
                address=request.address,
                notification_message=request.notification_message,
                notification_time=request.notification_time,
                blocked_numbers=[],
                last_updated=get_current_time(),
                calendarId='primary'
            )
        logging.debug("Updating business info")
        business.put()
        logging.info("Business info updated")
        return create_business_message(business)


    @endpoints.method(message_types.VoidMessage, message_types.VoidMessage,
                      path='notifications', http_method='GET',
                      name='notifications.send')
    def send_notifications(self, request):

        logging.info("send notifications job start (time: %d)" % get_current_time())

        appointments = Appointment.query(ndb.AND(Appointment.notification_time < get_current_time(),
                                                 Appointment.confirmation_status == ConfirmationStatus.unsent)).fetch()
        if appointments:
            logging.info("notifications to send: %d" % len(appointments))

            client = TwilioRestClient(TWILIO_ACCOUNT, TWILIO_TOKEN)
            bitly = bitly_api.Connection(access_token=BITLY_ACCESS_TOKEN)
            for apt in appointments:
                if not apt.customer:
                    continue
                logging.debug("appointment id: %d" % apt.key.id())
                if not apt.short_url:
                    self.create_short_url(bitly, apt)
                self.send_notification(client, apt)
                apt.confirmation_status = ConfirmationStatus.sent
                apt.put()

        logging.info("send notifications job end")
        return message_types.VoidMessage()


    def send_notification(self, client, apt):
        bi = BusinessInfo.query(BusinessInfo.user == apt.user).get()
        if not bi:
            logging.error('Appointment %d does not have associated business info' % apt.key.id())
            return
        notification_message = bi.notification_message.replace("{time}", to_pretty_date(apt.start_time)).replace("{link}", apt.short_url)
        customer = apt.customer.get()
        phone_number = customer.phone_number
        if phone_number[0] != '+':
            phone_number = "+972" + phone_number[1:]
        logging.info("send to customer [%s} notification [%s]" % (phone_number, notification_message))
        client.messages.create(to=phone_number, from_=TWILIO_PHONE_NUMBER,
                                 body=notification_message)

    @endpoints.method(AppointmentIdResourceContainer, AppointmentMessage,
                      path='appointment/confirm/{id}/{token}', http_method='PATCH',
                      name='appointment.confirm')
    def confirm_appointment(self, request):
        logging.info("confirm_appointment [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        apt = Appointment.get_by_id(int(request.id))
        if not apt or apt.deleted:
            logging.error('Appointment does not exist')
            raise endpoints.api_exceptions.BadRequestException('Appointment does not exist')
        if request.token != apt.confirmation_token:
            logging.error('Bad token')
            raise endpoints.api_exceptions.BadRequestException('Bad token')
        logging.info('Appointment with id %s exist' % request.id)
        apt.confirmation_status = ConfirmationStatus.confirmed
        apt.last_updated = get_current_time()
        logging.debug("Updating appointment")
        apt.put()
        logging.info("Appointment updated")
        return create_appointment_message(apt)

    @endpoints.method(AppointmentIdResourceContainer, AppointmentMessage,
                      path='appointment/decline/{id}/{token}', http_method='PATCH',
                      name='appointment.decline')
    def decline_appointment(self, request):
        logging.info("decline_appointment [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        apt = Appointment.get_by_id(int(request.id))
        if not apt or apt.deleted:
            logging.error('Appointment does not exist')
            raise endpoints.api_exceptions.BadRequestException('Appointment does not exist')
        if request.token != apt.confirmation_token:
            logging.error('Bad token')
            raise endpoints.api_exceptions.BadRequestException('Bad token')
        logging.info('Appointment with id %s exist' % request.id)
        apt.confirmation_status = ConfirmationStatus.declined
        apt.last_updated = get_current_time()
        logging.debug("Updating appointment")
        apt.put()
        logging.info("Appointment updated")
        return create_appointment_message(apt)

    @endpoints.method(AppointmentIdResourceContainer, message_types.VoidMessage,
                      path='customer/{id}/{token}', http_method='PATCH',
                      name='customer.block')
    def block_sender(self, request):
        logging.info("block_sender [user: %s] [request: %s]" % (self.get_endpoints_current_user(), request))
        apt = Appointment.get_by_id(int(request.id))
        if not apt or apt.deleted:
            logging.error('Appointment with id %s does not exist' % request.id)
            raise endpoints.api_exceptions.BadRequestException('Appointment does not exist')
        if request.token != apt.confirmation_token:
            logging.error('Bad token')
            raise endpoints.api_exceptions.BadRequestException('Bad token')

        logging.info('Appointment with id %s exist' % request.id)
        business = BusinessInfo.query(BusinessInfo.user==apt.user).get()
        business.blocked_numbers.append(apt.customer.get().phone_number)
        logging.debug("Updating business")
        business.put()
        logging.info("Business updated")

        return message_types.VoidMessage()


    def create_short_url(self, bitly, apt):
        logging.info("get bitly url for: %s" % apt.get_url())
        result = bitly.shorten(apt.get_url())
        logging.debug("bitly result: %s" % result['url'])
        apt.short_url = result['url']
        apt.put()

    RetrieveAccessTokenResourceContainer = endpoints.ResourceContainer(
        message_types.VoidMessage,
        exchange_token=messages.StringField(1, required=True))


    @endpoints.method(RetrieveAccessTokenResourceContainer, message_types.VoidMessage,
                      allowed_client_ids=allowed_clients_ids, audiences=[ANDROID_AUDIENCE], scopes=scopes,
                      path='user/auth/{exchange_token}', http_method='PUT',
                      name='user.auth')
    def retrieve_access_token(self, request):
        logging.info("retrieve access token [user: %s] [request: %s ]" % (self.get_endpoints_current_user(), request))
        business = BusinessInfo.query(BusinessInfo.user==self.get_endpoints_current_user()).get()
        if not business:
            logging.error("Business does not exist")
            endpoints.api_exceptions.ForbiddenException('Business does not exist')

        from oauth2client import GOOGLE_TOKEN_URI, GOOGLE_AUTH_URI, GOOGLE_REVOKE_URI
        from oauth2client.client import OAuth2WebServerFlow

        flow = OAuth2WebServerFlow(configs.WEB_CLIENT_ID,
                                   configs.CLIENT_SECRET,
                                   None,
                                   redirect_uri=None,
                                   auth_uri=GOOGLE_AUTH_URI,
                                   token_uri=GOOGLE_TOKEN_URI,
                                   revoke_uri=GOOGLE_REVOKE_URI,
                                   prompt=None
        )
        credentials = flow.step2_exchange(request.exchange_token)
        logging.info(credentials)
        business.access_token = credentials.access_token
        business.refresh_token = credentials.refresh_token
        business.token_expires = credentials.token_expiry
        business.put()

        return message_types.VoidMessage()



APPLICATION = endpoints.api_server([ShowUpApi])

